#ifndef TEST_PATRICIA_TRIE
#define TEST_PATRICIA_TRIE

#include "../src/estructuras/ArbolPatriciaTrie/PatriciaTrie.h"
#include "../src/estructuras/lista/Lista.h"

#include <iostream>
using namespace std;
#include <string>

#include <stdio.h>

typedef std::string tClavePatricia1;
typedef int tDatoPatricia1;

typedef PatriciaTrieNode<tClavePatricia1, tDatoPatricia1> tNodoPatricia;
typedef PatriciaTrie<tClavePatricia1, tDatoPatricia1> tPatricia;

typedef list<tNodoPatricia*> Lista_Nodos;
typedef typename list<tNodoPatricia*>::iterator it_Lista_Nodos;

//para almacenar los terminos que fallaron en la cargar de los terminos al patricia

class TerminoFallido{
private:
	tClavePatricia1 clave;
	tDatoPatricia1 dato;
public:
	TerminoFallido(){
		this->clave = ""; this->dato = 0;
	}
	TerminoFallido(	tClavePatricia1 clave, tDatoPatricia1 dato){
		this->clave = clave; this->dato = dato;
	}
};

static int cont1 = 0;
void paso1() {
	cout << "paso " << cont1++ << endl;
}

/*imprime las claves de el patricia con este formato:
 * i) pade  hermanoIzq  hermanoDer
 * todo (Ariel)no imprime en consola eclipse los hermanos en la primera pasada, pero los asccii si!
 * */
void imprimir_claves(tPatricia* patricia) {
	cout << "imprimir_claves(tPatricia* patricia)" << endl;
	Lista_Nodos lista_nodos = patricia->GetNodeList();
	it_Lista_Nodos it = lista_nodos.begin();
	int cont = 1;
	while (it != lista_nodos.end()) {
		tClavePatricia1 padre = (*it)->GetKey();
		tClavePatricia1 izq = (*it)->GetLeft()->GetKey();
		tClavePatricia1 der = (*it)->GetRight()->GetKey();
		cout << cont << ") " << padre << "\t" << izq << "  " << der << endl;
		*it++;
		cont++;
	}
}

/*
 * se prueba el metodo bit_get para la clave pasada por parametro
 * empieza a imprimir los bits desde la izquierda.
 * */
void imprimir_clave_en_bits(tPatricia* patricia, tClavePatricia1 clave,
		int cantBits_imprimibles) {
	cout << clave << "\t";
	for (int i = 0; i < cantBits_imprimibles; i++) {
		int bit = patricia->bit_get(clave, i);
		cout << bit << " ";
	}
	cout << endl;
}

/*
 * se prueba el metodo 'bit_get'para todas las claves de el arbol patricia
 * empieza a imprimir los bits desde la izquierda.
 * */
void imprimir_claves_en_bits(tPatricia* patricia, int cantBits_imprimibles) {
	cout << "imprimir_claves_en_bits(tPatricia* patricia, int cantBits_imprimibles)"<< endl;
	Lista_Nodos lista_nodos = patricia->GetNodeList();
	it_Lista_Nodos it = lista_nodos.begin();
	int cont = 1;
	while (it != lista_nodos.end()) {
		tClavePatricia1 claveActual = (*it)->GetKey();
		cout << cont << ") ";
		imprimir_clave_en_bits(patricia, claveActual, cantBits_imprimibles);
		*it++;
		cont++;
	}
}

/*
 * se prueba el metodo bit_get para la clave pasada por parametro
 * Para la lista de terminos
 * empieza a imprimir los bits desde la izquierda.
 * */
void imprimir_clave_en_bits(tClavePatricia1 clave, int cantBits_imprimibles) {
	tPatricia patricia;
	cout << clave << "\t";
	for (int i = 0; i < cantBits_imprimibles; i++) {
		int bit = patricia.bit_get(clave, i);
		cout << bit << " ";
	}
	cout << endl;
}
/*
 * se prueba el metodo 'bit_get'para todas las claves de la lista de terminos,
 * respectando el orden de aparicion
 * empieza a imprimir los bits desde la izquierda.
 * */
void imprimir_claves_en_bits(Lista<tClavePatricia1>* terminos,int cantBits_imprimibles) {
	cout<< "imprimir_claves_en_bits(Lista<tClavePatricia1>* terminos, int cantBits_imprimibles)"<< endl;
	IteradorLista<tClavePatricia1> it = terminos->iterador();
	int cont = 1;
	while (it.tieneSiguiente()) {
		tClavePatricia1 claveActual = it.siguiente();
		cout << cont << ") ";
		imprimir_clave_en_bits(claveActual, cantBits_imprimibles + 0);
		//cout<<cont<<") ";
		//imprimir_clave_en_bits(claveActual, cantBits_imprimibles+20);
		cont++;
		//cout<<endl;
	}
}
/*
 * se tiene una lista de nodos de el Patricia organizadas segun el metodo 'GetNodeList'
 * nroClave1 y nroClave2 son las posiciones de las claves de el patricia
 * que se utlizaran para comparar la diferencia en el primer bits.
 * ejemplo:
 * 101010000
 * 101110000 --> lo que se devuel es 3.
 * */
int posicion_diff_bits(tPatricia* patricia, int nroClave1, int nroClave2) {
	Lista_Nodos lista_nodos = patricia->GetNodeList();
	it_Lista_Nodos it = lista_nodos.begin();
	int cont = 0;
	tClavePatricia1 clave1;
	bool clave1_encontrado = false;
	int pos_return = -1;
	while (it != lista_nodos.end()) {
		tClavePatricia1 claveActual = (*it)->GetKey();
		if (cont == nroClave1) {
			clave1 = claveActual;
			clave1_encontrado = true;
		}
		if (cont == nroClave2 && clave1_encontrado)
			pos_return = patricia->bit_first_different(clave1, claveActual);
		*it++;
		cont++;
	}
	return pos_return;
}

void cargarListaDeTerminos(Lista<tClavePatricia1>* terminos) {
	cout << "cargarListaDeTerminos(Lista<tClavePatricia1>* terminos)" << endl;
	/*
	 FILE* fd = fopen(filename, "r");
	 char linea[20];
	 while (fgets(linea,20,fd) != NULL){
	 std::string termino = linea;
	 cout<<terminos<<endl;
	 terminos->agregar(termino);
	 }
	 */
	terminos->agregar("lata");
	terminos->agregar("lana");
	terminos->agregar("lapa");
	terminos->agregar("loza");
	terminos->agregar("lote");
	terminos->agregar("loro");
	terminos->agregar("luz");
	terminos->agregar("lani");
	terminos->agregar("lano");
}

int cargarPatricia(tPatricia* patricia, Lista<tClavePatricia1>* terminos,Lista<TerminoFallido>* terminosFallidos) {
	cout<<"cargarPatricia(tPatricia* patricia, Lista<tClavePatricia1>* terminos,"<<endl;
	int contAgregados = 0;
	int cantTerminos = 0;
	IteradorLista<tClavePatricia1> it = terminos->iterador();
	while (it.tieneSiguiente()) {
		//paso1();
		cantTerminos++;
		tClavePatricia1 claveActual = it.siguiente();
		tDatoPatricia1 datoActual = contAgregados;
		//tNodoPatricia* nodoAgregado = patricia->Insert(claveActual, datoActual);
		//si el actual no fue insertado, entonces lo agrego junto con terminos fallidos
		//todo POR ACA ME ESTA LARGANDO UN ERROR IDECIFRABLE. EL DEBUGER PINCHA POR QUE NO ENCUENTRA UN .SVN(???). RESULTA QUE EN OTRO PROYECTO ESTA PRUEBA ME ESTA ANDANDO COMO DEBE SER!
		if (!patricia->Insert(claveActual, datoActual)) {
			//cout<<"entro"<<endl;
			TerminoFallido terminoFallido(claveActual, datoActual);
			terminosFallidos->agregar(terminoFallido);
		}
		else{
			//cout<<"paso no NULL"<<endl;
			contAgregados++;
		}
	}
	return (cantTerminos - contAgregados);
}

void operaciones_en_patricia(tPatricia* patricia) {

	// Remove some items from the structure
	/*
	 printf("Deleting 'casa'... %s\n", patricia->Delete("casa") ? "OK" : "Uh-oh!");
	 printf("Deleting 'caza'... %s\n", patricia->Delete("caza") ? "OK" : "Uh-oh!");

	 // Lookup
	 printf("Looking up 'casa'... %s\n", patricia->LookupNode("casa") ? "Still there!" : "Not there (OK).");
	 printf("Looking up 'caza'... %s\n", patricia->LookupNode("caza") ? "Still there!" : "Not there (OK).");
	 */
}

void testPatricia1() {
	cout << "INICIA: testPatricia1()" << endl;
	Lista<tClavePatricia1>* terminos = new Lista<tClavePatricia1> ();
	Lista<TerminoFallido>* terminosFallidos = new Lista<TerminoFallido>();
	tPatricia* patricia = new tPatricia();

	cargarListaDeTerminos(terminos);
	int cantTerminos_noAgregados = 0;
	cantTerminos_noAgregados = cargarPatricia(patricia, terminos, terminosFallidos);
	//todo Mier... que no pasa por aca. No tiene mucha importancia ya que el testManejadorPatricia tiene la misma funcionalidad y esta funcionando bien!!!
	cout<<"cantTerminos_noAgregados: "<<cantTerminos_noAgregados<<endl;

	imprimir_claves(patricia);

	imprimir_claves_en_bits(terminos, 8);

	imprimir_claves_en_bits(patricia, 8);

}

void testPatricia2() {
	cout << "INICIA: testPatricia2()" << endl;
}

#endif
